﻿/*
Copyright (C) 2010 INOUE Hiroyuki

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

using System;
using System.IO;
using AC = System.Security.AccessControl;
using NTAccount = System.Security.Principal.NTAccount;
using CodePlex.Dombly.DiskUsage.BusinessLogic.Extensions;

namespace CodePlex.Dombly.DiskUsage.BusinessLogic
{
    /// <summary>
    /// Provides the properties for information of files.
    /// </summary>
    public class File : FileSystem<FileInfo>, IFile
    {
        #region static properties
        /// <summary>
        /// Gets or sets whether to count file size as file length or 
        /// size on disk.
        /// </summary>
        public static bool UseClusterSize { get; set; }
        #endregion

        #region IFileSystem implementations

        /// <summary>
        /// Gets the directory count of current file, which is defined 
        /// to be zero for a file.
        /// </summary>
        public override int DirectoryCount { get { return 0; } }
        
        /// <summary>
        /// Gets the file count of current file, which is defined 
        /// to be one.
        /// </summary>
        public override int FileCount { get { return 1; } } 
       
        /// <summary>
        /// Gets the size of current file in bytes.
        /// </summary>
        public override long FileSize
        {
            get
            {
                return UseClusterSize
                    ? this.ClusterSize
                    : this._Info.Length;
            }
        }
        
        /// <summary>
        /// Gets the owner of current file.
        /// </summary>
        public override string Owner
        {
            get
            {
                var ac = new AC.FileSecurity(
                    this._Info.FullName,
                    AC.AccessControlSections.Owner);
                var id = (NTAccount)ac.GetOwner(typeof(NTAccount));
                return id.ToString();
            }
        }
        
        #endregion

        #region properties

        #region IsCompressed
        /// <summary>
        /// Gets a value whether the file is compressed.
        /// </summary>
        public bool IsCompressed
        { get { return this._Info.Length != this.CompressedSize; } }
        #endregion

        #region CompressedSize
        /// <summary>
        /// Gets the compressed size of current file in bytes.
        /// </summary>
        public long CompressedSize
        {
            get
            {
                if (!this._CompressedSize.HasValue)
                    try
                    {
                        this._CompressedSize = this._Info.GetCompressedSize();
                    }
                    catch
                    {
                        this._CompressedSize = this._Info.Length;
                    }
                return this._CompressedSize.Value;
            }
        }
        private long? _CompressedSize;
        #endregion

        #region ClusterSize
        /// <summary>
        /// Gets actual disk usage of current file with consideration of 
        /// the compression and the cluster size of file system.
        /// </summary>
        public long ClusterSize
        {
            get
            {
                if (!this._ClusterSize.HasValue)
                {
                    long bytesPerCluster = this._Info.GetBytesPerCluster();
                    long clusters = ((long)(this.CompressedSize / bytesPerCluster))
                                  + ((long)(this.CompressedSize % bytesPerCluster) == 0L ? 0L : 1L);
                    this._ClusterSize = bytesPerCluster* clusters;
                }
                return this._ClusterSize.Value;
            }
        }
        private long? _ClusterSize;
        #endregion

        #endregion

        #region constructors
        internal File(FileInfo info, IDirectory parent)
            : base(info, parent)
        {
            if (FileScanning != null)
                FileScanning(this, new EventArgs());

            if (FileScanCompleted != null)
                this.ScanCompleted += FileScanCompleted;
            this.Scanned = DateTime.Now;
        }
        #endregion

        #region events
        /// <summary>
        /// Occurs when the scan of any instance of this class is beginning.
        /// </summary>
        public static event EventHandler FileScanning;
        /// <summary>
        /// Occurs when the scan of any instance of this class is completed.
        /// </summary>
        public static event EventHandler FileScanCompleted;
        #endregion
    }
}
